package com.zhaokuner.springcloudconfigserver.utils;

import lombok.Data;
import org.apache.commons.lang.StringUtils;

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;

/**
 * <p>Description: 时间处理类</p>
 * <p>
 * <p>Copyright:  2018-至今 北京掌通未来科技有限公司.All rights reserved.</p>
 *
 * @author dingran
 * @date 2019/6/28
 **/
public class MyDateUtils {

    public static final String TIME_FORMAT = "HH:mm:ss";
    public static final String DATE_FORMAT = "yyyy-MM-dd";
    public static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

    /**
     * yyyy-MM-dd HH:mm:ss
     */
    public static DateTimeFormatter normalDateTimeFormatter = DateTimeFormatter.ofPattern(DATETIME_FORMAT);
    /**
     * yyyy-MM-dd
     */
    public static DateTimeFormatter normalDateFormatter = DateTimeFormatter.ofPattern(DATE_FORMAT);
    /**
     * HH:mm:ss
     */
    public static DateTimeFormatter normalTimeFormatter = DateTimeFormatter.ofPattern(TIME_FORMAT);


    /**
     * @return 当前微秒时间
     */
    public static Long getMicroTime() {
        long currentTime = System.currentTimeMillis() * 1000;
        long nanoTime = System.nanoTime();
        return currentTime + nanoTime % 1000000 / 1000;
    }

    /**
     * @return 当前纳秒时间
     */
    public static Long getNanoTime() {
        long currentTime = System.currentTimeMillis() * 1000000;
        long nanoTime = System.nanoTime();
        return currentTime + nanoTime % 1000000;
    }

    /**
     * LocalDateTime转Date
     *
     * @param localDateTime
     * @return
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        if (localDateTime == null) {
            return null;
        }
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * Date转LocalDateTime
     *
     * @param date
     * @return
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        if (date == null) {
            return null;
        }

        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * LocalDate转Date
     *
     * @param localDate
     * @return
     */
    public static Date localDateToDate(LocalDate localDate) {
        if (localDate == null) {
            return null;
        }

        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    /**
     * Date转LocalDate
     *
     * @param date
     * @return
     */
    public static LocalDate dateToLocalDate(Date date) {
        if (date == null) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * 日期时间（LocalDateTime）按默认格式转字符串
     * <p>
     * yyyy-MM-dd HH:mm:ss
     *
     * @param dateTime
     * @return
     */
    public static String localDateTimeFormat(LocalDateTime dateTime) {
        return localDateTimeFormat(dateTime, normalDateFormatter);
    }

    /**
     * 日期时间（LocalDateTime）按指定格式转字符串
     *
     * @param value
     * @param formatDate
     * @return
     */
    public static String localDateTimeFormat(LocalDateTime value, DateTimeFormatter formatDate) {
        if (null == value || null == formatDate) {
            return "";
        }
        return value.format(formatDate);
    }

    /**
     * 日期时间（LocalDateTime）按指定格式转字符串
     *
     * @param value
     * @param format
     * @return
     */
    public static String localDateTimeFormat(LocalDateTime value, String format) {
        String dateString;
        if (value == null) {
            dateString = "";
        } else {
            DateTimeFormatter formatDate = DateTimeFormatter.ofPattern(format);
            dateString = value.format(formatDate);
        }

        return dateString;
    }


    /**
     * 字符串按默认格式转日期时间（LocalDateTime）
     * <p>
     * yyyy-MM-dd HH:mm:ss
     *
     * @param str
     * @return
     */
    public static LocalDateTime strToLocalDateTime(String str) {
        return strToLocalDateTime(str, normalDateTimeFormatter);
    }

    /**
     * 字符串按指定格式转日期时间（LocalDateTime）
     *
     * @param str
     * @param format
     * @return
     */

    /**
     * 字符串按指定格式转日期时间（LocalDateTime）
     *
     * @param str
     * @param format
     * @return
     */
    public static LocalDateTime strToLocalDateTime(String str, DateTimeFormatter format) {
        if (StringUtils.isEmpty(str) || null == format) {
            return null;
        }
        try {
            return LocalDateTime.parse(str, format);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 字符串按指定格式转日期时间（LocalDateTime）
     *
     * @param str
     * @param format
     * @return
     */
    public static LocalDateTime strToLocalDateTime(String str, String format) {
        if (StringUtils.isEmpty(str) || StringUtils.isEmpty(format)) {
            return null;
        }
        DateTimeFormatter formatDate = DateTimeFormatter.ofPattern(format);
        try {
            return LocalDateTime.parse(str, formatDate);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 时间转字符串 默认 yyyy-MM-dd HH:mm:ss 格式转换
     *
     * @param str 字符串
     * @return
     */
    public static Date stringToDate(String str, String format) {
        if (StringUtils.isBlank(str) || StringUtils.isBlank(format)) {
            return null;
        }
        return localDateTimeToDate(strToLocalDateTime(str, format));
    }

    /**
     * 时间转字符串
     *
     * @param str 字符串
     * @return
     */
    public static Date strToDate(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        return localDateTimeToDate(strToLocalDateTime(str));
    }

    /**
     * 字符串转时间 默认 yyyy-MM-dd HH:mm:ss 格式转换
     *
     * @param date 时间
     * @return
     */
    public static String dateToStr(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    /**
     * 字符串转时间
     *
     * @param date 时间
     * @return
     */
    public static String dateToString(Date date, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    /**
     * 计算2个日期之间相差的  以年、月、日为单位，各自计算结果是多少
     * 比如：2011-02-02 到  2017-03-02
     * 以年为单位相差为：6年
     * 以月为单位相差为：73个月
     * 以日为单位相差为：2220天
     *
     * @param fromDate 起始时间
     * @param toDate   截止时间
     * @return
     */
    public static DayCompare dayCompare(Date fromDate, Date toDate) {
        Calendar from = Calendar.getInstance();
        from.setTime(fromDate);
        Calendar to = Calendar.getInstance();
        to.setTime(toDate);
        //只要年月
        int fromYear = from.get(Calendar.YEAR);
        int fromMonth = from.get(Calendar.MONTH);
        int toYear = to.get(Calendar.YEAR);
        int toMonth = to.get(Calendar.MONTH);
        int year = toYear - fromYear;
        int month = toYear * 12 + toMonth - (fromYear * 12 + fromMonth);
        int day = (int) ((to.getTimeInMillis() - from.getTimeInMillis()) / (24 * 3600 * 1000));
        return new DayCompare(year, month, day);
    }

    @Data
    public static class DayCompare {
        private int year;
        private int month;
        private int day;

        public DayCompare() {

        }

        /**
         * 方法描述：DayCompare
         *
         * @param year  年
         * @param month 月
         * @param day   馹
         * @author: 丁冉 DingRan 2019/6/28
         */
        public DayCompare(int year, int month, int day) {
            this.year = year;
            this.month = month;
            this.day = day;
        }
    }

    /**
     * 格式化后的日期字符串，默认使用 yyyy-MM-dd HH:mm:ss
     *
     * @param localDateTime
     * @return formatDateToString
     */
    public static String formatDateToString(LocalDateTime localDateTime) {
        return localDateTime.format(normalDateTimeFormatter);
    }


    /**
     * 字符转换为时间，默认使用yyyy-MM-dd HH:mm:ss格式
     *
     * @param date
     * @return LocalDateTime
     */
    public static LocalDateTime formatStrToDate(String date) {
        return LocalDateTime.parse(date, normalDateTimeFormatter);
    }

    /**
     * 字符转换为时间，默认使用yyyy-MM-dd HH:mm:ss格式
     *
     * @param data   日期字符串
     * @param format 转换格式
     * @return LocalDateTime
     */
    public static LocalDateTime formatStringToDate(String data, String format) {
        if (null != data && !data.equals("")) {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format);
            return LocalDateTime.parse(data, dateTimeFormatter);
        } else {
            return null;
        }
    }

    /**
     * 将LocalDateTime转为long类型的timestamp
     *
     * @param localDateTime
     * @return long
     */
    public static long getTimestamp(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zoneId).toInstant();
        return instant.toEpochMilli();
    }

    /**
     * 将long类型的timestamp转为LocalDateTime
     *
     * @param timestamp
     * @return LocalDateTime
     */
    public static LocalDateTime getLocalDateTime(long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        ZoneId zoneId = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zoneId);
    }


    /**
     * 判断是否为闰年
     *
     * @param data 日期 格式:yyyy-MM-dd
     * @return boolean
     */
    public static boolean isLeapYear(String data) {
        LocalDate yeat = LocalDate.parse(data);
        return yeat.isLeapYear();
    }

    /**
     * 判断是否为闰年
     *
     * @param localDate 日期 格式:yyyy-MM-dd
     * @return boolean
     */
    public static boolean isLeapYear(LocalDate localDate) {
        return localDate.isLeapYear();
    }

    /**
     * 计算两个时间相差多少年，结果为负数说明前面的时间比后面的时间大
     *
     * @param time1 时间一
     * @param time2 时间二
     * @return long
     */
    public static long minusYears(String time1, String time2) {
        LocalDateTime localDateTime = formatStrToDate(time1);
        LocalDateTime localDateTime2 = formatStrToDate(time2);
        return ChronoUnit.YEARS.between(localDateTime, localDateTime2);
    }

    /**
     * 计算两个时间相差多少月，结果为负数说明前面的时间比后面的时间大
     *
     * @param time1 时间一
     * @param time2 时间二
     * @return long
     */
    public static long minusMonths(String time1, String time2) {
        LocalDateTime localDateTime = formatStrToDate(time1);
        LocalDateTime localDateTime2 = formatStrToDate(time2);
        return ChronoUnit.MONTHS.between(localDateTime, localDateTime2);
    }

    /**
     * 计算两个时间相差多少天，结果为负数说明前面的时间比后面的时间大
     *
     * @param time1 时间一
     * @param time2 时间二
     * @return long
     */
    public static long minusDays(String time1, String time2) {
        LocalDateTime localDateTime = formatStrToDate(time1);
        LocalDateTime localDateTime2 = formatStrToDate(time2);
        return ChronoUnit.DAYS.between(localDateTime, localDateTime2);
    }

    /**
     * 计算两个时间相差多少星期，结果为负数说明前面的时间比后面的时间大
     *
     * @param time1 时间一
     * @param time2 时间二
     * @return long
     */
    public static long minusWeeks(String time1, String time2) {
        LocalDateTime localDateTime = formatStrToDate(time1);
        LocalDateTime localDateTime2 = formatStrToDate(time2);
        return ChronoUnit.WEEKS.between(localDateTime, localDateTime2);
    }

    /**
     * 计算两个时间相差多少小时，结果为负数说明前面的时间比后面的时间大
     *
     * @param time1 时间一
     * @param time2 时间二
     * @return long
     */
    public static long minusHours(String time1, String time2) {
        LocalDateTime localDateTime = formatStrToDate(time1);
        LocalDateTime localDateTime2 = formatStrToDate(time2);
        return ChronoUnit.HOURS.between(localDateTime, localDateTime2);
    }

    /**
     * 计算两个时间相差多少分钟，结果为负数说明前面的时间比后面的时间大
     *
     * @param time1 时间一
     * @param time2 时间二
     * @return long
     */
    public static long minusMinutes(String time1, String time2) {
        LocalDateTime localDateTime = formatStrToDate(time1);
        LocalDateTime localDateTime2 = formatStrToDate(time2);
        return ChronoUnit.MINUTES.between(localDateTime, localDateTime2);
    }

    /**
     * 计算两个时间相差多少秒，结果为负数说明前面的时间比后面的时间大
     *
     * @param time1 时间一
     * @param time2 时间二
     * @return long
     */
    public static long minusSeconds(String time1, String time2) {
        LocalDateTime localDateTime = formatStrToDate(time1);
        LocalDateTime localDateTime2 = formatStrToDate(time2);
        return ChronoUnit.MINUTES.between(localDateTime, localDateTime2);
    }

    /**
     * 获取传入时间的年份
     *
     * @param localDateTime 时间
     * @return
     */
    public static int getYear(LocalDateTime localDateTime) {
        return localDateTime.getYear();
    }


    /**
     * 一天的0点和24点
     */
    public static class Day {
        /**
         * 毫秒 0点
         */
        public Long clock0 = 0L;
        /**
         * 毫秒 24点
         */
        public Long clock24 = 24L;
        /**
         * 秒 0点
         */
        public Integer clock0Second = 0;
        /**
         * 秒 24点
         */
        public Integer clock24Second = 24;
    }

    /**
     * 获取某一天的0点和24点
     */
    public static Day getDay(Long millis) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(millis);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Day today = new Day();
        today.clock0 = cal.getTimeInMillis();
        today.clock0Second = (int) (today.clock0 / 1000);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 999);
        today.clock24 = cal.getTimeInMillis();
        today.clock24Second = (int) (today.clock24 / 1000);
        return today;
    }


    /**
     * 中国 周一~周日
     */
    public static class Week {
        public Long firstDayMonday0 = 0L;
        public Long lastDaySunday24 = 0L;
        public Integer firstDayMonday0Second = 0;
        public Integer lastDaySunday24Second = 0;
    }


    /**
     * 中国 周一~周日
     */
    public static Week getWeek(Long millisecond) {
        Week w = new Week();
        /** 以下先根据第一个时间找出所在周的星期一、星期日, 再对第二个时间进行比较 */
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(millisecond);
        // 判断要计算的日期是否是周日，如果是则减一天计算周六的，否则会出问题，计算到下一周去了
        // 获得当前日期是一个星期的第几天
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }
        // 设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int day = cal.get(Calendar.DAY_OF_WEEK);
        // 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        w.firstDayMonday0 = cal.getTimeInMillis();
        w.firstDayMonday0Second = (int) (w.firstDayMonday0 / 1000);
        cal.add(Calendar.DATE, 6);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 999);
        w.lastDaySunday24 = cal.getTimeInMillis();
        w.lastDaySunday24Second = (int) (w.lastDaySunday24 / 1000);

        return w;
    }

    /**
     * 月 第一天 ~~ 最后一天
     */
    public static class Month {
        public Long firstDay0 = 0L;
        public Long lastDay24 = 0L;
        public Integer firstDay0Second = 0;
        public Integer lastDay24Second = 0;
    }

    /**
     * 月 第一天 ~~ 最后一天
     */
    public static Month getMonth(Long millisecond) {
        Month m = new Month();

        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(millisecond);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        m.firstDay0 = cal.getTimeInMillis();
        m.firstDay0Second = (int) (m.firstDay0 / 1000);

        cal.add(Calendar.MONTH, 1);
        cal.add(Calendar.DAY_OF_MONTH, -1);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 999);
        m.lastDay24 = cal.getTimeInMillis();
        m.lastDay24Second = (int) (m.lastDay24 / 1000);

        return m;
    }

    /**
     * 年  第一天 ~~ 最后一天
     */
    public static class Year {
        public Long firstDay0 = 0L;
        public Long lastDay24 = 0L;
        public Integer firstDay0Second = 0;
        public Integer lastDay24Second = 0;
    }

    /**
     * 年  第一天 ~~ 最后一天
     */
    public static Year getYear(Long millisecond) {
        Year y = new Year();
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(millisecond);
        cal.set(Calendar.DAY_OF_YEAR, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        y.firstDay0 = cal.getTimeInMillis();
        y.firstDay0Second = (int) (y.firstDay0 / 1000);

        cal.add(Calendar.YEAR, 1);
        cal.add(Calendar.DAY_OF_YEAR, -1);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 999);
        y.lastDay24 = cal.getTimeInMillis();
        y.lastDay24Second = (int) (y.lastDay24 / 1000);

        return y;
    }

}
